/**
 * 
 */
package at.ac.lbg.media.vis.framework.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import flex.messaging.io.amf.ASObject;

import at.ac.lbg.media.vis.framework.domain.CategoryDO;
import at.ac.lbg.media.vis.framework.model.Category;
import at.ac.lbg.media.vis.framework.persistence.ICategoryDAO;

/**
 * @author Evelyn Münster
 *
 */
public class CategoryService implements ICategoryService {
	
	private ICategoryDAO categoryDAO;
	private List<CategoryDO> keywords;
	// local data cache
	private Map<Integer, List<CategoryDO>> categories = new HashMap<Integer, List<CategoryDO>>();
	// key for data cache
	public static final Integer ALL_SECTIONS = -1;
	private List<CategoryDO> sections;
	
	protected final Log logger = LogFactory.getLog(getClass());
	
	public CategoryService() {}
	
	@Override
	public List<CategoryDO> getKeywords() {
		if (keywords != null) {
			return keywords;
		}
		keywords = categoryDAO.getKeywords();
		return keywords;
	}
	
	@Override
	public List<CategoryDO> getCategoryStructure() {
		if (categories.containsKey(ALL_SECTIONS)) {
			return categories.get(ALL_SECTIONS);
		}
		List<CategoryDO> cats = categoryDAO.getCategories();
		// fill children of maincats
		List<CategoryDO> keywords = getKeywords();
		for (CategoryDO main : cats) {
			for (CategoryDO keyword : keywords) {
				if (keyword.getParentCategory().compareTo(main) == 0) {
					main.getChildren().add(keyword);
				}
			}
			logger.debug(main.getName() + ": " + main.getChildren().size());
		}
		categories.put(ALL_SECTIONS, cats);
		return cats;
	}
	
   @Override
    public List<CategoryDO> getCategoryStructure(int sectionId) {
        if (categories.containsKey(sectionId)) {
            return categories.get(sectionId);
        }
        // Here we build the hierarchical structure of categories and keywords.
        // TODO Maybe this is also possible with hibernate and even better?
        List<CategoryDO> cats = categoryDAO.getCategories(sectionId);
        // fill children of maincats
        List<CategoryDO> keywords = getKeywords();
        for (CategoryDO main : cats) {
            for (CategoryDO kw : keywords) {
                if (kw.getParentCategory().compareTo(main) == 0) {
                    main.getChildren().add(kw);
                }
            }
            //logger.debug(main.getName() + ": " + main.getChildren().size());
        }
        categories.put(sectionId, cats);
        return cats;
    }
   
    @Override
    public List<CategoryDO> getSections() {
        // look in the cache first
        if (sections != null) {
            return sections;
        }
        sections = categoryDAO.getSections();
        return sections;
    }
	
	/**
	 * TODO make sure that only one instance per category
	 * is initialized for Category.
	 */
	@Override
	public List<Category> translate(List<CategoryDO> categoryDOs) {
		List<Category> cats = new ArrayList<Category>();
		for (CategoryDO cDO : categoryDOs) {
			cats.add(translate(cDO));
		}
		return cats;
	}
	
	@Override
	public Category translate(CategoryDO cDO) {
		Category c = new Category();
		c.setId(cDO.getId());
		c.setName(cDO.getName());
		if (cDO.getCountartworks() != null) {
		    c.setCountArtworks(cDO.getCountartworks());
	    } else {
	        c.setCountArtworks(0);
	    }
		if (cDO.getParentCategory() != null) {
			c.setParent(translate(cDO.getParentCategory()));
		}
		if (cDO.getChildren().size() > 0) {
			c.setChildren(translate(cDO.getChildren()));
		}
		return c;
	}

	/**
	 * @param categoryDAO Dependency Injection
	 */
	public void setCategoryDAO(ICategoryDAO categoryDAO) {
		this.categoryDAO = categoryDAO;
	}

    @Override
    public List<CategoryDO> convertToCategories(List<Object> categories) {
        List<CategoryDO> list = new ArrayList<CategoryDO>();
        for (Object c : categories) {
            ASObject asObj = (ASObject) c;
            CategoryDO catDO = new CategoryDO();
            catDO.setId(((Integer)asObj.get("id")).longValue());
            catDO.setName((String)asObj.get("name"));
            list.add(catDO);
        }
        return list;
    }
    
    @Override
    public List<CategoryDO> filter(List<CategoryDO> keywords, int sectionId) {
        List<CategoryDO> filteredKeywords = new ArrayList<CategoryDO>();
        List<CategoryDO> sectionCats = getCategoryStructure(sectionId);
        List<CategoryDO> sectionKeywords = new ArrayList<CategoryDO>();
        for (CategoryDO sc : sectionCats) {
            sectionKeywords.addAll(sc.getChildren());
        }
        for (CategoryDO kw : keywords) {
            for (CategoryDO sectionKw: sectionKeywords) {
                if (kw.getId().intValue() == sectionKw.getId().intValue()) {
                    filteredKeywords.add(sectionKw);
                    break;
                }
            }
        }
        return filteredKeywords;
    }
	
	

}
